home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
umddvi
/
lib
/
font.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
9KB
|
418 lines
/*
* Copyright (c) 1987 University of Maryland Department of Computer Science.
* All rights reserved. Permission to copy for any purpose is hereby granted
* so long as this copyright notice remains intact.
*/
#ifndef lint
static char rcsid[] = "$Header: font.c,v 2.6 87/06/16 18:27:56 chris Exp $";
#endif
/*
* Routines for working with fonts. In particular, the configuration
* dependent code is here.
*
* Specific fonts (GF, PXL, etc.) have functions in separate files.
*/
#include <stdio.h>
#include <errno.h>
#include "types.h"
#include "conv.h"
#include "font.h"
/*
* Define the default configuration file.
* Also define the maximum path name length.
*/
#ifndef CONFFILE
#define CONFFILE "/usr/local/lib/tex/fontdesc"
#endif
#define PATHLEN 1024
/*
* A font configuration. The font list is ordered.
*
* A specifier is typically a particular print engine, since
* different engines need slightly different fonts.
*/
struct fontconf {
struct fontconf *fc_next;
struct fontops *fc_ops;
char *fc_path; /* path, with metacharacters */
char *fc_spec; /* specifier */
int fc_slop; /* slop value */
};
/*
* EQ is a fast way to check for string equivalence.
*/
#define EQ(a, b) (*(a) == *(b) && strcmp(a, b) == 0)
/*
* Private variables.
*/
static int didinit; /* true => initialised already */
static char *cfname; /* config file name, for errors */
static int cfline; /* config file line, likewise */
static struct fontops *fontops;/* font operations code: list head */
static struct fontconf *fonts; /* font list */
static struct fontconf **nextfc;/* used during initialisation */
static char spec_any[] = "*"; /* the `anything' specifier */
/*
* Imports.
*/
extern int errno;
char *getenv(), *malloc(), *strsave();
#ifndef sys5
char *sprintf();
#endif
/*
* Here, alas, we know about all the kinds of fonts.
* This also means that every DVI interpreter pulls in
* the full set of font manipulation routines.
*
* PERHAPS THIS SHOULD BE CONFIGURABLE.
*/
#define ADDFONT(x) { \
extern struct fontops x; \
x.fo_next = fontops; \
fontops = &x; \
}
fontinit(file)
char *file;
{
if (didinit) {
/*
* Could free the old configuration and fire up
* a new one, but for now . . .
*/
error(1, 0, "attempt to reinit fonts");
/* NOTREACHED */
}
didinit++;
ADDFONT(boxops);
ADDFONT(blankops);
ADDFONT(invisops);
ADDFONT(pxlops);
ADDFONT(pkops);
ADDFONT(gfops);
nextfc = &fonts;
if (file == NULL)
if ((file = getenv(CONFENV)) == NULL)
file = CONFFILE;
readconf(file);
}
/*
* A proto resembles a fontspec (indeed, it is a prototype
* fontspec) but is not quite the same. It is used to gather
* the information needed per fontspec before allocating
* the fontspec itself.
*/
struct proto {
char *p_type;
char *p_spec;
char *p_slop;
char *p_path;
};
/*
* Read the named configuration file. The file is split into
* lines, and lines are split into words; if the first word is
* "font", this is a fontconf, and we read the remainder of the
* words and make a fontconf entry.
*/
static
readconf(name)
char *name;
{
register FILE *f; /* config file */
register char **p; /* pointer into word vector */
register int c;
char line[1024]; /* input line */
char *v[100]; /* word vector */
struct proto proto; /* prototype fontconf */
#define GETWORD(x, ifnone) \
if (--c <= 0) \
badcf(ifnone); \
else \
(x) = *p++
if ((f = fopen(name, "r")) == NULL)
error(1, errno, "cannot read font configuration file \"\%s\"",
name);
cfname = name;
cfline = 0;
while (fgets(line, sizeof (line), f) != NULL) {
cfline++;
if ((c = strlen(line)) > 0) {
if (line[--c] != '\n')
badcf("line too long");
line[c] = 0;
}
if ((c = split(line, v, sizeof (v) / sizeof (*v))) < 0)
badcf("too many words");
p = v;
/* skip things that are not fonts */
if (c == 0 || !EQ(*p, "font"))
continue;
p++;
GETWORD(proto.p_type, "missing font typename");
GETWORD(proto.p_spec, "missing font spec (engine)");
GETWORD(proto.p_slop, "missing slop value");
GETWORD(proto.p_path, "need pathname");
(void) setfont(&proto);
}
}
/*
* Find a font's operations, given its name.
*/
static struct fontops *
findops(name)
register char *name;
{
register struct fontops *fo;
for (fo = fontops; fo != NULL; fo = fo->fo_next)
if (EQ(fo->fo_name, name))
return (fo);
return (NULL);
}
/*
* Turn a prototype fontconf into a real one.
*/
static int
setfont(p)
register struct proto *p;
{
register struct fontconf *fc;
struct fontops *ops = findops(p->p_type);
if (ops == NULL) {
error(0, 0,
"\"%s\", line %d: unknown font type \"%s\" ignored",
cfname, cfline, p->p_type);
return (-1);
}
if ((fc = (struct fontconf *) malloc(sizeof (*fc))) == NULL)
error(1, errno,
"out of memory for font configuration (sorry)");
fc->fc_ops = ops;
fc->fc_next = NULL;
fc->fc_path = strsave(p->p_path);
fc->fc_spec = EQ(p->p_spec, spec_any) ? NULL : strsave(p->p_spec);
fc->fc_slop = atoi(p->p_slop);
if (fc->fc_slop < 1) /* quietly enforce proper slops */
fc->fc_slop = 1;
*nextfc = fc;
nextfc = &fc->fc_next;
return (0);
}
/*
* Complain about a problem in the configuration file.
*/
static
badcf(why)
char *why;
{
error(1, 0, "\"%s\", line %d: %s", cfname, cfline, why);
/* NOTREACHED */
}
/*
* Turn a prototype path, name, and magnification into a full
* path.
*/
static
pave(result, proto, name, mag)
char *result, *proto, *name;
int mag;
{
register int c;
register char *s, *d, *p;
char num[30];
d = result;
p = proto;
s = NULL;
num[0] = 0; /* will need changing for other bases */
while (p != NULL) {
/*
* If sourcing from s, take its next character, and
* insert it directly. Otherwise take the next path
* character and interpret it.
*/
if (s != NULL) {
if ((c = *s++) == 0) {
s = NULL;
continue;
}
goto put;
}
if ((c = *p++) == 0)
p = NULL;
if (c != '%')
goto put;
switch (c = *p++) {
case 'f':
case 'n':
case 's':
s = name;
continue;
case 'd':
case 'm':
if (num[0] == 0)
(void) sprintf(num, "%d", mag);
s = num;
continue;
case 0:
c = '%';
p--;
/* FALLTHROUGH */
}
put:
if (d - result >= PATHLEN)
error(1, 0, "font path `%s' too long (sorry)", proto);
*d++ = c;
}
}
struct font *getafont(); /* get a font and optional rasters */
/*
* Given a font name and size, return the first font that fits, along
* with its name (via fname). If we cannot find such a font, we set
* *fname to point to a `canonical' example font name, unless there are
* are no fonts for the device, in which case we set *fname to NULL.
*/
struct font *
GetFont(nm, dvimag, dvidsz, dev, fname)
char *nm;
i32 dvimag, dvidsz;
char *dev, **fname;
{
return (getafont(nm, dvimag, dvidsz, dev, fname, 1));
}
/*
* Same as GetFont, but caller promises never to ask for rasters.
*/
struct font *
GetRasterlessFont(nm, dvimag, dvidsz, dev, fname)
char *nm;
i32 dvimag, dvidsz;
char *dev, **fname;
{
return (getafont(nm, dvimag, dvidsz, dev, fname, 0));
}
/*
* NEED TO THINK ABOUT gf NAMING CONVENTIONS HERE: ARE THEY LIKE pxl?
* WHAT ABOUT OTHERS?
*/
static struct font *
getafont(nm, dvimag, dvidsz, dev, fname, wantrast)
char *nm;
i32 dvimag, dvidsz;
char *dev, **fname;
int wantrast;
{
register int slop, fmag;
register struct font *f;
register struct fontconf *fc;
register char *path;
static char firstpath[PATHLEN], laterpath[PATHLEN];
double mag;
int scaled;
if (!didinit)
fontinit((char *) NULL);
/*
* The equation below means, approximately, `the font is
* magnified by the ratio of the actual size dvimag to the
* design size dvidsz, and then further scaled by the
* global magnification.' We multiply this by the printer's
* resolution in dots per inch, then use the per-font
* conversion factor to convert a dots-per-inch value to
* a font name `%m' magnification (extension).
*/
mag = (double) dvimag / (double) dvidsz;
scaled = mag * 1000.0 + 0.5;
mag *= Conversion.c_mag * Conversion.c_dpi;
path = firstpath;
for (fc = fonts; fc != NULL; fc = fc->fc_next) {
if (dev != NULL && fc->fc_spec != NULL &&
!EQ(dev, fc->fc_spec))
continue;
fmag = mag * fc->fc_ops->fo_dpitomag + 0.5;
for (slop = 0; slop < fc->fc_slop; slop++) {
pave(path, fc->fc_path, nm, fmag + slop);
if (access(path, 4) == 0)
goto found;
if (slop) {
pave(path, fc->fc_path, nm, fmag - slop);
if (access(path, 4) == 0)
goto found;
}
path = laterpath;
}
}
/* not found */
if (path == firstpath) { /* never got to try any paths */
*fname = NULL;
errno = ENXIO;
} else {
*fname = firstpath;
errno = ENOENT;
}
return (NULL);
found:
*fname = path;
/* allocate space for the per-font info, and read it in */
f = (struct font *) malloc(sizeof (struct font));
if (f == NULL)
return (NULL);
f->f_flags = wantrast ? FF_RASTERS : 0;
f->f_ops = fc->fc_ops;
f->f_path = strsave(path);
f->f_font = strsave(nm);
f->f_dvimag = dvimag;
f->f_dvidsz = dvidsz;
f->f_scaled = scaled;
f->f_checksum = 0; /* in case the font reader cannot get one */
errno = 0;
if ((*f->f_ops->fo_read)(f)) {
int e = errno; /* paranoid */
free(f->f_path);
free(f->f_font);
free((char *) f);
errno = e;
return (NULL);
}
return (f);
}